package com.mobimagic.lockscreen.util;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Binder;
import android.os.Build;
import android.util.Log;

import com.mobimagic.lockscreen.AppEnv;
import com.mobimagic.lockscreen.sdk.LockScreenSDK;
import com.qihoo360.mobilesafe.core.utils.RunningProcessUtil;

/**
 * @author tanmingfeng
 */
public class OpsCheckUtil {

    private static final boolean DEBUG = AppEnv.bAppdebug;
    private static final String TAG = "OpsCheckerUtil";
    public static final String OPSTR_GET_USAGE_STATS = "android:get_usage_stats";

    /**
     * 是否获得Usage权限
     *
     * @param c
     * @return
     */
    public static boolean getUsageEnable(Context c) {
        return OpsCheckUtil.checkOp(OPSTR_GET_USAGE_STATS, Binder.getCallingUid(), LockScreenSDK.getInstance()
                .getPkgName(), c) == 0;
    }

    /**
     * 是否需要UsageAccess授权
     *
     * @param context
     * @return
     */
    public static boolean isNeedGetUsageAcccessPermission(Context context) {
        return !OpsCheckUtil.isRunningAppProcessesEnable(context) && !OpsCheckUtil.getUsageEnable(context);
    }

    public static boolean isRunningAppProcessesEnable(Context context) {
        return RunningProcessUtil.isRunningAppProcessesEnable(context);
    }

    /**
     * 检查是否准许悬SystemAlterWindow的权限
     *
     * @param context
     * @return
     */
    public static boolean isOpsAllowedSystemAlterWindow(Context context) {
        //https://developer.android.com/reference/android/app/AppOpsManager.html
        //api 19
        if (Build.VERSION.SDK_INT < 19) {
            return true;
        }
        try {
            Object o = OpsCheckUtil.checkOpNoThrow(context);
            if (o != null) {
                if (DEBUG) {
                    Log.i(TAG, "checkOpNoThrow has error");
                }
                if (o instanceof Integer) {
                    Integer mode = (Integer) o;
                    if (DEBUG) {
                        Log.i(TAG, "mode===" + mode);
                    }
                    if (mode == 0) {
                        return true;
                    } else {
                        return false;
                    }
                }
            } else {
                if (DEBUG) {
                    Log.e(TAG, "checkOpNoThrow has error");
                }
            }

        } catch (Exception e) {
            if (DEBUG) {
                Log.e(TAG, "isOpsAllowed has error", e);
            }
        }
        return true;
    }

    private static Object checkOpNoThrow(Context context) {
        PackageManager packageManager = context.getPackageManager();
        ApplicationInfo applicationInfo = null;
        try {
            applicationInfo = packageManager.getApplicationInfo(context.getPackageName(), 0);
        } catch (NameNotFoundException e1) {
            return null;

        }

        Object AppOpsManager = context.getSystemService("appops");
        Method checkOpNoThrow = OpsCheckUtil.getReflectedMethod(AppOpsManager, "checkOpNoThrow", int.class, int.class,
                String.class);
        if (checkOpNoThrow != null) {
            try {
                int op_type = 24;
                try {
                    @SuppressWarnings("rawtypes")
                    Class temp = AppOpsManager.getClass();
                    Field field = temp.getField("OP_SYSTEM_ALERT_WINDOW");
                    op_type = (Integer) field.get(null);
                    if (DEBUG) {
                        Log.i(TAG, "op_type===" + op_type);
                    }
                } catch (NoSuchFieldException e) {
                    if (DEBUG) {
                        Log.e(TAG, "get OP_SYSTEM_ALERT_WINDOW has error", e);
                    }
                }
                Object o = checkOpNoThrow.invoke(AppOpsManager, op_type, applicationInfo.uid,
                        applicationInfo.packageName);

                return o;
            } catch (IllegalArgumentException e) {
                if (DEBUG) {
                    Log.e(TAG, "checkOpNoThrow has error", e);
                }

            } catch (IllegalAccessException e) {
                if (DEBUG) {
                    Log.e(TAG, "checkOpNoThrow has error", e);
                }

            } catch (Exception e) {
                if (DEBUG) {
                    Log.e(TAG, "checkOpNoThrow has error", e);
                }
            }
        }
        return null;
    }

    /**
     * AppOpsManager mAppOpsManager = (AppOpsManager) c.getSystemService(Context.APP_OPS_SERVICE);
     * mAppOpsManager.checkOp(op, uid, packageName);
     *
     * @param op
     * @param uid
     * @param packageName
     * @param context
     * @return
     */
    public static int checkOp(String op, int uid, String packageName, Context context) {
        try {
            Object AppOpsManager = context.getSystemService("appops");
            Method checkOpNoThrow = OpsCheckUtil.getReflectedMethod(AppOpsManager, "checkOp", String.class, int.class,
                    String.class);
            if (checkOpNoThrow != null) {
                Object o = checkOpNoThrow.invoke(AppOpsManager, op, uid, packageName);
                if (o != null) {
                    if (DEBUG) {
                        Log.i(TAG, "checkOp has error");
                    }
                    if (o instanceof Integer) {
                        Integer mode = (Integer) o;
                        if (DEBUG) {
                            Log.i(TAG, "mode===" + mode);
                        }
                        return mode;
                    }
                } else {
                    if (DEBUG) {
                        Log.e(TAG, "checkOp has error");
                    }
                }
            }
        } catch (IllegalArgumentException e) {
            if (DEBUG) {
                Log.e(TAG, "checkOp has error", e);
            }

        } catch (IllegalAccessException e) {
            if (DEBUG) {
                Log.e(TAG, "checkOp has error", e);
            }

        } catch (Exception e) {
            if (DEBUG) {
                Log.e(TAG, "checkOp has error", e);
            }
        }

        return 0;
    }

    private static Method getReflectedMethod(Object am, String methodname, Class<?>... args) {

        Method temp = null;
        try {
            temp = am.getClass().getMethod(methodname, args);
        } catch (SecurityException e) {

            return null;
        } catch (NoSuchMethodException e) {

            return null;
        }
        return temp;
    }

}
